package io.geekidea.boot.system.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.geekidea.boot.framework.page.OrderByItem;
import io.geekidea.boot.framework.page.Paging;
import io.geekidea.boot.system.dto.ResourceDto;
import io.geekidea.boot.system.mapper.ResourceMapper;
import io.geekidea.boot.system.query.ResourceQuery;
import io.geekidea.boot.system.query.SysDictQuery;
import io.geekidea.boot.system.service.ResourceService;
import io.geekidea.boot.system.vo.ResourceVo;
import io.geekidea.boot.system.entity.Resource;
import io.geekidea.boot.system.vo.SysDictVo;
import io.geekidea.boot.util.PagingUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 资源管理 服务实现类
 */
@Service
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource> implements ResourceService {

    private static final Logger logger = LoggerFactory.getLogger(ResourceServiceImpl.class);

    @Autowired
    private ResourceMapper resourceMapper;

    private String uploadPath = System.getProperty("user.dir") + java.io.File.separator + "uploads"
            + java.io.File.separator; // 动态获取上传路径

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResourceVo addResource(ResourceDto dto) {
        logger.info("Adding resource: {}", dto);

        Resource resource = new Resource();
        BeanUtils.copyProperties(dto, resource);

        // 保存资源，save方法返回boolean类型
        boolean saved = save(resource);
        if (!saved) {
            // 保存失败则抛出异常以便事务回滚
            throw new RuntimeException("保存资源失败");
        }

        // 保存成功后，将resource转换为ResourceVo
        ResourceVo resourceVo = new ResourceVo();
        BeanUtils.copyProperties(resource, resourceVo);

        logger.info("Resource added: {}", resourceVo);
        return resourceVo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateResource(ResourceDto dto) {
        logger.info("Updating resource: {}", dto);
        Resource resource = getById(dto.getId());
        if (resource == null) {
            logger.error("Resource not found: {}", dto.getId());
            throw new RuntimeException("资源不存在");
        }
        BeanUtils.copyProperties(dto, resource);
        boolean result = updateById(resource);
        logger.info("Resource updated: {}", result);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteResource(Long id) {
        logger.info("Deleting resource: {}", id);

        // 1. 获取资源文件信息
        Resource resource = getById(id);
        if (resource == null) {
            logger.error("Resource not found: {}", id);
            throw new RuntimeException("资源不存在");
        }

        // 2. 删除数据库记录
        boolean dbResult = removeById(id);
        if (!dbResult) {
            logger.error("Failed to delete resource record: {}", id);
            throw new RuntimeException("数据库记录删除失败");
        }

        // 3. 删除物理文件及目录
        try {
            // 删除文件
            if (StringUtils.isNotBlank(resource.getFilePath())) {
                Path filePath = Paths.get(resource.getFilePath());
                if (Files.exists(filePath)) {
                    Files.delete(filePath);
                    logger.info("Deleted physical file: {}", resource.getFilePath());
                }
            }

            // 删除目录（使用接口参数id而不是resource对象）
            Path dirPath = Paths.get(uploadPath + id);
            if (Files.exists(dirPath)) {
                Files.walk(dirPath)
                        .sorted(Comparator.reverseOrder())
                        .map(Path::toFile)
                        .forEach(File::delete);
                logger.info("Deleted resource directory: {}", dirPath);
            }
        } catch (IOException e) {
            logger.error("物理文件删除失败，资源ID：{}", id, e);
            // 文件系统操作失败不影响事务回滚
            throw new RuntimeException("文件删除失败，请联系管理员");
        }

        logger.info("Resource deleted successfully: {}", id);
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deletePhysicalFile(Long id) {
        logger.info("Deleting resource: {}", id);

        // 1. 获取资源文件信息
        Resource resource = getById(id);
        if (resource == null) {
            logger.error("Resource not found: {}", id);
            throw new RuntimeException("资源不存在");
        }

        // 2. 删除物理文件（如果存在）
        if (StringUtils.isNotBlank(resource.getFilePath())) {
            try {
                Path filePath = Paths.get(resource.getFilePath());
                if (Files.exists(filePath)) {
                    Files.delete(filePath);
                    logger.info("Deleted physical file: {}", resource.getFilePath());
                }
            } catch (IOException e) {
                logger.error("Failed to delete physical file: {}", resource.getFilePath(), e);
                // 物理文件删除失败不影响数据库记录删除
            }
        }
        return true;

    }

    @Override
    public ResourceVo getResourceById(Long id) {
        logger.info("Getting resource by id: {}", id);
        ResourceVo resource = resourceMapper.getResourceById(id);
        logger.info("Resource retrieved: {}", resource);
        return resource;
    }

//    @Override
//    public List<ResourceVo> getResourceList(ResourceQuery query) {
//        logger.info("Getting resource list with query: {}", query);
//        List<ResourceVo> resourceList = resourceMapper.getResourceList(query);
//        logger.info("Resource list retrieved: {}", resourceList);
//        return resourceList;
//    }


    @Override
    public Paging<ResourceVo> getResourcePage(ResourceQuery query) {
        PagingUtil.handlePage(query, OrderByItem.orderBy("grade desc,id"));
        List<ResourceVo> list = resourceMapper.getResourcePage(query);
        Paging<ResourceVo> paging = new Paging<>(list);
        return paging;
    }

    @Override
    public Map<String, Object> uploadResource(MultipartFile file, ResourceDto dto) {
        logger.info("Uploading resource file with data: {}", dto);

        try {
            Resource resource;
            if (dto.getId() == null) {
                // 新增时创建新记录
                resource = new Resource();
                BeanUtils.copyProperties(dto, resource);
                resource.setVersion(StringUtils.isNotBlank(dto.getVersion()) ? dto.getVersion() : "v1.0.0");
                resource.setName(StringUtils.isNotBlank(dto.getName()) ? dto.getName() : "resource-" + System.currentTimeMillis());
                save(resource);
            } else {
                // 更新时获取现有记录
                resource = getById(dto.getId());
                if (resource == null) {
                    throw new RuntimeException("资源不存在");
                }
                BeanUtils.copyProperties(dto, resource);
                updateById(resource);
            }

            // 创建资源目录
            String filePath = String.format("%s%d%s",
                    uploadPath,
                    resource.getId(),
                    File.separator);

            File uploadDir = new File(filePath);
            if (!uploadDir.exists()) {
                uploadDir.mkdirs();
            }

            // 生成唯一文件名
            String fileExt = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
            String originalFilename = file.getOriginalFilename();
            String fileExtension = StringUtils.substringAfterLast(originalFilename, ".");
            String fileName = UUID.randomUUID().toString() + (StringUtils.isNotBlank(fileExtension) ? "." + fileExtension : "");
            File dest = new File(filePath + fileName);
            file.transferTo(dest);

            // 更新资源记录
            resource.setFileName(fileName);
            resource.setFilePath(dest.getAbsolutePath());
            resource.setFileSize(file.getSize());
            updateById(resource);

            logger.info("Resource file uploaded successfully, id: {}", resource.getId());
            Map<String, Object> result = new HashMap<>();
            result.put("id", resource.getId());
            result.put("fileName", resource.getFileName());
            result.put("filePath", resource.getFilePath());
            result.put("fileSize", resource.getFileSize());
            return result;
        } catch (Exception e) {
            logger.error("Failed to upload resource file: {}", file.getOriginalFilename(), e);
            throw new RuntimeException("文件上传失败", e);
        }
    }

    @Override
    public Path downloadResource(Long id) {
        logger.info("Preparing to download resource with id: {}", id);
        Resource resource = getById(id);
        if (resource == null) {
            logger.error("Resource not found for download: {}", id);
            throw new RuntimeException("NOT_FOUND:资源不存在");
        }

        if (StringUtils.isBlank(resource.getFilePath())) {
            logger.error("File path is empty for resource: {}", id);
            throw new RuntimeException("BAD_REQUEST:文件路径未配置");
        }

        Path filePath = Paths.get(resource.getFilePath());
        try {
            if (!Files.exists(filePath)) {
                logger.error("Physical file not found at path: {}", filePath);
                throw new RuntimeException("文件不存在或已被删除");
            }

            if (!Files.isReadable(filePath)) {
                logger.error("File not readable: {}", filePath);
                throw new RuntimeException("文件不可读");
            }

            // 验证文件大小
            long fileSize = Files.size(filePath);
            if (fileSize == 0) {
                logger.error("Empty file detected: {}", filePath);
                throw new RuntimeException("文件内容为空");
            }

            logger.info("File validated for download: {} (size: {} bytes)", filePath, fileSize);
            return filePath;
        } catch (IOException e) {
            logger.error("File validation failed for resource: {}, error: {}", id, e.getMessage());
            throw new RuntimeException("文件校验失败: " + e.getMessage());
        }
    }
}
